import type { ComponentStyleIdType } from '../../../types/interfaces'
import { StyleManager } from '../../../module/style_manager'
import { ComponentStyleMode, IS_PRODUCTION, logger } from '../../../types/constants'
import { StylesService } from '../../../types/constants/styles'
import { IconService } from '../../icons'
import { GMStorage } from '../storage/gm_storage'
import { ThemeVarService } from '../style/theme_var/service'

/**
 * 元素选择器配置类型
 * - selector: 选择器字符串或动态查询函数
 * - dynamic: 是否为动态选择器
 * - unique: 是否为唯一选择器（可选），仅做标记，不影响查询逻辑，如果是公共可复用组件，必须一个唯一的选择器
 */
export interface ElementSelectors {
  [key: string]: { selector: string | ((...args: any[]) => string), dynamic: boolean, unique?: boolean, isRoot?: boolean }
}
/**
 * 动态查询函数类型
 */
export type JQueryDynamicQuery = (...args: any[]) => JQueryElement
/**
 * 元素集合类型（支持静态元素和动态查询函数）
 */
export interface JQueryElementsCollection {
  [key: string]: JQueryElement | JQueryDynamicQuery
}

/**
 * 基础组件属性
 */
export interface BaseComponentProps {
  id?: string
  idClass?: string
}

// ⚠️⚠️⚠️创建组件需要在一个包裹容器中，不然通过 find 找不到元素
export abstract class UIComponent<P extends BaseComponentProps = BaseComponentProps> extends GMStorage {
  // 组件描述
  protected description: string = ''
  // 组件属性（使用泛型定义 props）
  readonly props: P
  // 挂载的元素容器
  $element: JQueryElement = undefined
  protected $container: JQueryElement = undefined
  // 组件样式 ID
  protected styleId: ComponentStyleIdType | string = ''
  // 缓存的元素集合
  private _cachedElements: {
    elements: JQueryElementsCollection
    allFound: boolean // 标记所有元素是否都存在
  } | null = null

  // 抽象属性，由子类实现
  abstract ELEMENT_SELECTORS: ElementSelectors
  protected componentStyleType: ComponentStyleMode = ComponentStyleMode.Static

  protected themeVarService: ThemeVarService = ThemeVarService.getInstance()
  protected iconService: IconService = IconService.getInstance()
  protected stylesService: StylesService = StylesService.getInstance()

  protected constructor(props?: P) {
    super()
    this.props = props || ({} as P)
  }

  /**
   * 获取元素集合
   */
  get elements(): JQueryElementsCollection {
    return this.getElements()
  }

  /**
   *  获取组件名称 - 自动将类名作为 name
   */
  get name(): ComponentStyleIdType {
    return this.constructor.name as ComponentStyleIdType
  }

  /**
   *  获取组件的『最外层类名』 - 自动将类名转为小写中划线格式作为 className
   *  ⚠️ 【注意】类名需要在渲染 HTML 时作为 class 应用
   */
  get className(): string {
    const name = this.constructor.name
      .replace(/([a-z])([A-Z])/g, '$1-$2')
      .toLowerCase()

    return IS_PRODUCTION ? name : `dev-component-${name}`
  }

  /**
   * 获取组件的选择器
   */
  protected get selector(): string {
    return `.${CSS.escape(this.className)}`
  }

  /**
   * 标识是否为动态 DOM（默认 false）
   * - true: 每次调用 `getElements()` 都重新查询 DOM（适合频繁变化的 DOM 结构）
   * - false: 缓存查询结果（适合静态 DOM 结构）
   */
  protected readonly isDynamicDOM: boolean = false

  /**
   * 根据选择器配置生成元素集合
   */
  createElements<T extends ElementSelectors>(
    $container: JQuery<HTMLElement> | undefined,
    selectors: T,
  ): {
    [K in keyof T]: T[K] extends (...args: infer P) => string
      ? (...args: P) => JQuery<HTMLElement>
      : JQuery<HTMLElement>
  } {
    const elements: any = {}

    for (const [key, config] of Object.entries(selectors)) {
      // 根元素特殊处理
      if (config.isRoot) {
        elements[key] = $container || $()
        continue
      }

      if (typeof config.selector === 'function') {
        elements[key] = (...args: any[]) => $container?.find((config.selector as (...args: any[]) => string)(...args)) || $()
      }
      else {
        elements[key] = $container?.find(config.selector) || $()
      }
    }

    return elements
  }

  /**
   * 计算元素并检查存在性（子类无需关心缓存逻辑）
   */
  private calculateElements() {
    const elements = this.getLatestElements()
    const allFound = elements && Object.values(elements).every(el => el && el?.length > 0)
    return { elements, allFound }
  }

  /**
   * 获取最新组件的元素
   */
  getLatestElements(): JQueryElementsCollection {
    return this.createElements(this.$element, this.ELEMENT_SELECTORS)
  }

  /**
   * 获取所有元素并自动检查存在性
   */
  getElements(): JQueryElementsCollection {
    // 动态 DOM 或缓存无效时重新查询
    if (this.isDynamicDOM || !this._cachedElements || !this._cachedElements.allFound) {
      this._cachedElements = this.calculateElements()
    }
    return this._cachedElements.elements
  }

  /**
   * 访问指定元素
   */
  protected getElement<K extends keyof JQueryElementsCollection>(
    key: K,
    ...args: any
  ): JQueryElement {
    const config = this.ELEMENT_SELECTORS[key]

    if (!config) {
      logger.warn(`[${this.name}] 未定义的元素选择器: "${key}"`)
      return undefined
    }

    // 如果为动态选择器，直接返回查询结果，无需缓存处理
    if (config.dynamic) {
      return typeof config.selector === 'function' ? this.$element?.find(config.selector(...args)) : this.$element?.find(config.selector)
    }

    const element = this.elements[key]
    return typeof element === 'function' ? (element as (...args: any[]) => JQueryElement)(...args) : element
  }

  /**
   * 检查元素是否存在且有效
   * @param element 要检查的jQuery元素
   * @returns 元素是否有效
   */
  protected isElementValid(element?: JQuery<HTMLElement>): element is JQuery<HTMLElement> {
    return !!element && element.length > 0
  }

  /**
   * 检查主元素是否存在且有效
   */
  protected isMainElementValid(): boolean {
    return this.isElementValid(this.$element)
  }

  /**
   * 渲染组件 HTML
   */
  abstract render(...args: any[]): string | void

  /**
   * 获取组件样式
   */
  protected getStyles(): string {
    return ''
  }

  /**
   * 挂载到容器
   * @param container 容器元素
   */
  mount(container: JQuery<HTMLElement>): void {
    const longestPrefixOptions = this.props?.id ? `组件ID: ${this.props.id}` : ''

    if (!container || !container.length) {
      logger.warn(`[${this.name}] ${longestPrefixOptions} 无法挂载，挂载容器不存在`)
      return
    }

    this.$element = container.find(this.selector)

    if (!this.$element || !this.$element.length) {
      logger.warn(`[${this.name}] ${longestPrefixOptions} 无法挂载，未找到匹配的选择器: "${this.selector}"`)
      return
    }

    // 1. 先更新 DOM（非常重要！！！）
    this.updateDOM()
    // 2. 获取组件所有元素
    this.getElements()
    // 3. 再绑定事件
    this.bindEvents()
    // 4.打印资源信息
    this.printResourceStats()
  }

  /**
   * 绑定事件处理程序
   */
  protected bindEvents(): void {}

  /**
   * 重置组件状态
   */
  protected reset(): void {
    if (!this.$element || !this.$element.length) {
      logger.warn(`[${this.name}] 元素未挂载，跳过重置`)
      // eslint-disable-next-line no-useless-return
      return
    }
  }

  /**
   * 更新 UI 显示
   */
  protected updateUI(..._args: any[]): void {
    if (!this.$element || !this.$element.length) {
      logger.warn(`[${this.name}] 无法更新UI: 元素未挂载`)
      // eslint-disable-next-line no-useless-return
      return
    }
  }

  /**
   * DOM 更新
   */
  protected updateDOM(): void {
    // 清除缓存
    this.clearCache()
  }

  getValue(): string | undefined {
    return undefined
  }

  /**
   * 强制清除元素缓存（手动触发）
   */
  protected clearCache(): void {
    this._cachedElements = null
  }

  /**
   * 注册组件样式
   */
  protected registerStyles(): void {
    const styles = this.getStyles()

    if (!this.styleId) {
      logger.warn(`[${this.name}] 样式 ID 不存在`)
      return
    }

    if (styles && styles.length > 0) {
      StyleManager.getInstance().registerStyle(this.styleId, styles, false, true, this.componentStyleType === ComponentStyleMode.Dynamic)
    }
  }

  /**
   * 注销组件样式
   */
  protected unregisterStyles(): void {
    if (this.styleId) {
      StyleManager.getInstance().unregisterStyle(this.styleId, true)
    }
  }

  destroy(): void {
    this.removeEventListeners()
    this.cleanupReferences()
    this.removeStyleTag()
    // 暂不注销样式
    // this.unregisterStyles()
  }

  /**
   * 移除事件监听器
   */
  removeEventListeners(): void {}

  /**
   * 清理引用
   */
  cleanupReferences(): void {}

  /**
   * 移除样式标签
   */
  removeStyleTag(): void {}
}
